#include <xboot.h>
#include <input/keyboard.h>
#include <graphic/surface.h>
#include <graphic/region.h>

static const char zh_CN[] = X({
	"Window Info": "窗口信息",
	"Button": "按钮",
});

static void xui_style_color(struct xui_context_t * ctx, struct color_t * c)
{
	struct region_t * r;
	unsigned int id;

	xui_push_id(ctx, &c, sizeof(struct color_t *));
	id = xui_get_id(ctx, &c, sizeof(struct color_t *));
	r = xui_layout_next(ctx);
	xui_control_update(ctx, id, r, 0);
	if((ctx->active == id) && (ctx->mouse.down & XUI_MOUSE_LEFT))
	{
		xui_open_popup(ctx, "!cpopup");
	}
	xui_draw_checkerboard(ctx, r->x, r->y, r->w, r->h);
	xui_draw_rectangle(ctx, r->x, r->y, r->w, r->h, 0, 0, c);
	if(xui_begin_popup(ctx, "!cpopup"))
	{
		int width = 300;
		int height = 220;
		int sw = (width - ctx->style.layout.spacing * 3) / 4;
		float h, s, v, a;
		xui_layout_row(ctx, 1, (int[]){ width }, height);
		xui_colorpicker(ctx, c);
		xui_layout_row(ctx, 4, (int[]){ sw, sw, sw, sw }, 0);
		xui_number_uchar_ex(ctx, &c->r, 0, 255, 1, "R : %.0f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT);
		xui_number_uchar_ex(ctx, &c->g, 0, 255, 1, "G : %.0f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT);
		xui_number_uchar_ex(ctx, &c->b, 0, 255, 1, "B : %.0f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT);
		xui_number_uchar_ex(ctx, &c->a, 0, 255, 1, "A : %.0f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT);
		color_get_hsva(c, &h, &s, &v, &a);
		if(xui_number_float_ex(ctx, &h, 0, 1, 0.01, "H : %.2f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT))
			color_set_hsva(c, h, s, v, a);
		if(xui_number_float_ex(ctx, &s, 0, 1, 0.01, "S : %.2f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT))
			color_set_hsva(c, h, s, v, a);
		if(xui_number_float_ex(ctx, &v, 0, 1, 0.01, "V : %.2f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT))
			color_set_hsva(c, h, s, v, a);
		if(xui_number_float_ex(ctx, &a, 0, 1, 0.01, "A : %.2f", XUI_NUMBER_PRIMARY | XUI_OPT_TEXT_LEFT))
			color_set_hsva(c, h, s, v, a);
		xui_end_popup(ctx);
	}
	xui_pop_id(ctx);
}

static void style_window(struct xui_context_t * ctx)
{
	if(xui_begin_window(ctx, "Style Window", &(struct region_t){ 20, 20, (ctx->screen.w - 60) / 2, ctx->screen.h - 40 }))
	{
		if(xui_begin_tree(ctx, "Color"))
		{
			if(xui_begin_tree(ctx, "Primary"))
			{
			if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.primary.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.primary.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.primary.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.primary.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.primary.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.primary.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.primary.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.primary.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.primary.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			if(xui_begin_tree(ctx, "Secondary"))
			{
				if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.secondary.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.secondary.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.secondary.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.secondary.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.secondary.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.secondary.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.secondary.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.secondary.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.secondary.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			if(xui_begin_tree(ctx, "Success"))
			{
				if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.success.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.success.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.success.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.success.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.success.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.success.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.success.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.success.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.success.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			if(xui_begin_tree(ctx, "Info"))
			{
				if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.info.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.info.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.info.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.info.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.info.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.info.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.info.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.info.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.info.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			if(xui_begin_tree(ctx, "Warning"))
			{
				if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.warning.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.warning.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.warning.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.warning.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.warning.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.warning.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.warning.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.warning.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.warning.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			if(xui_begin_tree(ctx, "Danger"))
			{
				if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.danger.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.danger.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.danger.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.danger.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.danger.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.danger.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.danger.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.danger.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.danger.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			if(xui_begin_tree(ctx, "Light"))
			{
				if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.light.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.light.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.light.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.light.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.light.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.light.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.light.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.light.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.light.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			if(xui_begin_tree(ctx, "dark"))
			{
				if(xui_begin_tree(ctx, "Normal"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.dark.normal.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.dark.normal.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.dark.normal.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Hover"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.dark.hover.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.dark.hover.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.dark.hover.border);
					xui_end_tree(ctx);
				}
				if(xui_begin_tree(ctx, "Focus"))
				{
					xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
					xui_label(ctx, "Background :");
					xui_style_color(ctx, &ctx->style.dark.active.background);
					xui_label(ctx, "Foreground :");
					xui_style_color(ctx, &ctx->style.dark.active.foreground);
					xui_label(ctx, "Border :");
					xui_style_color(ctx, &ctx->style.dark.active.border);
					xui_end_tree(ctx);
				}
				xui_end_tree(ctx);
			}
			xui_end_tree(ctx);
		}
		if(xui_begin_tree(ctx, "Font"))
		{
			xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
			xui_label(ctx, "Color :");
			xui_style_color(ctx, &ctx->style.font.color);
			xui_label(ctx, "Size :");
			xui_number_int(ctx, &ctx->style.font.size, 8, 72, 1);
			xui_end_tree(ctx);
		}
		if(xui_begin_tree(ctx, "Layout"))
		{
			xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
			xui_label(ctx, "Width :");
			xui_number_int(ctx, &ctx->style.layout.width, 8, 256, 1);
			xui_label(ctx, "Height :");
			xui_number_int(ctx, &ctx->style.layout.height, 8, 72, 1);
			xui_label(ctx, "Padding :");
			xui_number_int(ctx, &ctx->style.layout.padding, 0, 32, 1);
			xui_label(ctx, "Spacing :");
			xui_number_int(ctx, &ctx->style.layout.spacing, 0, 32, 1);
			xui_label(ctx, "Indent :");
			xui_number_int(ctx, &ctx->style.layout.indent, 0, 32, 1);
			xui_end_tree(ctx);
		}
		xui_end_window(ctx);
	}
}

static void overview_window(struct xui_context_t * ctx)
{
	static const char * wcstr[] = {
		"Primary",
		"Secondary",
		"Success",
		"Info",
		"Warning",
		"Danger",
		"Light",
		"Dark",
	};

	if(xui_begin_window(ctx, "Overview Window", &(struct region_t){ 40 + (ctx->screen.w - 60) / 2, 20, (ctx->screen.w - 60) / 2, ctx->screen.h - 40 }))
	{
		struct xui_container_t * win = xui_get_container(ctx);
		win->region.w = max(win->region.w, 48);
		win->region.h = max(win->region.h, 48);

		if(xui_begin_tree(ctx, T("Window Info")))
		{
			struct xui_container_t * win = xui_get_container(ctx);
			xui_layout_row(ctx, 2, (int[]){ 100, -1 }, 0);
			xui_label(ctx, "Position :");
			xui_label(ctx, xui_format(ctx, "%d, %d", win->region.x, win->region.y));
			xui_label(ctx, "Size :");
			xui_label(ctx, xui_format(ctx, "%d, %d", win->region.w, win->region.h));
			xui_label(ctx, "Frame :");
			xui_label(ctx, xui_format(ctx, "%d", ctx->frame));
			xui_label(ctx, "Fps :");
			xui_label(ctx, xui_format(ctx, "%d", ctx->fps));
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, T("Button")))
		{
			if(xui_begin_tree(ctx, "Normal Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0, wcstr[i], (i << 8) | XUI_OPT_TEXT_CENTER);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0, wcstr[i], (i << 8) | XUI_OPT_TEXT_CENTER | XUI_BUTTON_ROUNDED);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Outline Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0, wcstr[i], (i << 8) | XUI_OPT_TEXT_CENTER | XUI_BUTTON_OUTLINE);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Outline Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0, wcstr[i], (i << 8) | XUI_OPT_TEXT_CENTER | XUI_BUTTON_ROUNDED | XUI_BUTTON_OUTLINE);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Normal Icon Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0xf000 + i, NULL, (i << 8) | XUI_OPT_TEXT_CENTER);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Icon Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0xf000 + i, NULL, (i << 8) | XUI_OPT_TEXT_CENTER | XUI_BUTTON_ROUNDED);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Outline Icon Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0xf000 + i, NULL, (i << 8) | XUI_OPT_TEXT_CENTER | XUI_BUTTON_OUTLINE);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Outline Icon Button"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 40);
				for(int i = 0; i < 8; i++)
				{
					xui_button_ex(ctx, 0xf000 + i, NULL, (i << 8) | XUI_OPT_TEXT_CENTER | XUI_BUTTON_ROUNDED | XUI_BUTTON_OUTLINE);
				}
				xui_end_tree(ctx);
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Checkbox"))
		{
			static int states[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
			for(int i = 0; i < 8; i++)
			{
				xui_checkbox_ex(ctx, wcstr[i], &states[i], (i << 8));
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Radio"))
		{
			static enum option_t {
				PRIMARY,
				SECONDARY,
				SUCCESS,
				INFO,
				WARNING,
				DANGER,
				LIGHT,
				DARK,
			} op = PRIMARY;
			if(xui_radio_ex(ctx, wcstr[0], (op == PRIMARY), XUI_RADIO_PRIMARY))
				op = PRIMARY;
			if(xui_radio_ex(ctx, wcstr[1], (op == SECONDARY), XUI_RADIO_SECONDARY))
				op = SECONDARY;
			if(xui_radio_ex(ctx, wcstr[2], (op == SUCCESS), XUI_RADIO_SUCCESS))
				op = SUCCESS;
			if(xui_radio_ex(ctx, wcstr[3], (op == INFO), XUI_RADIO_INFO))
				op = INFO;
			if(xui_radio_ex(ctx, wcstr[4], (op == WARNING), XUI_RADIO_WARNING))
				op = WARNING;
			if(xui_radio_ex(ctx, wcstr[5], (op == DANGER), XUI_RADIO_DANGER))
				op = DANGER;
			if(xui_radio_ex(ctx, wcstr[6], (op == LIGHT), XUI_RADIO_LIGHT))
				op = LIGHT;
			if(xui_radio_ex(ctx, wcstr[7], (op == DARK), XUI_RADIO_DARK))
				op = DARK;
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Toggle"))
		{
			static int states[8] = { 1, 1, 1, 1, 1, 1, 1, 1 };
			for(int i = 0; i < 8; i++)
			{
				xui_toggle_ex(ctx, &states[i], (i << 8));
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Slider"))
		{
			static double h[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
			xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
			for(int i = 0; i < 8; i++)
			{
				xui_slider_ex(ctx, &h[i], 0, 100, 0, (i << 8) | XUI_SLIDER_HORIZONTAL);
			}
			static double v[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
			xui_layout_row(ctx, 8, (int[]){ 24, 24, 24, 24, 24, 24, 24, -1 }, 160);
			for(int i = 0; i < 8; i++)
			{
				xui_slider_ex(ctx, &v[i], 0, 100, 0, (i << 8) | XUI_SLIDER_VERTICAL);
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Number"))
		{
			if(xui_begin_tree(ctx, "Normal Number"))
			{
				static double n[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
				xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_number_ex(ctx, &n[i], -1000, 1000, 1, "%.2f", (i << 8) | XUI_OPT_TEXT_LEFT);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Number"))
			{
				static double n[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
				xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_number_ex(ctx, &n[i], -1000, 1000, 1, "%.2f", (i << 8) | XUI_OPT_TEXT_LEFT | XUI_NUMBER_ROUNDED);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Outline Number"))
			{
				static double n[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
				xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_number_ex(ctx, &n[i], -1000, 1000, 1, "%.2f", (i << 8) | XUI_OPT_TEXT_LEFT | XUI_NUMBER_OUTLINE);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Outline Number"))
			{
				static double n[8] = { 10, 20, 30, 40, 50, 60, 70, 80 };
				xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_number_ex(ctx, &n[i], -1000, 1000, 1, "%.2f", (i << 8) | XUI_OPT_TEXT_LEFT | XUI_NUMBER_ROUNDED | XUI_NUMBER_OUTLINE);
				}
				xui_end_tree(ctx);
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Collapse"))
		{
			xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
			for(int i = 0; i < 8; i++)
			{
				if(xui_collapse_ex(ctx, 0xf000 + i, wcstr[i], (i << 8) | XUI_OPT_TEXT_LEFT))
					xui_label(ctx, xui_format(ctx, "This is %s", wcstr[i]));
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Textedit"))
		{
			static char buf[128];
			xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
			if(xui_textedit(ctx, buf, sizeof(buf)) & (1 << 1))
			{
				buf[0] = 0;
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Colorpicker"))
		{
			static struct color_t c = { 0xff, 0xff, 0xff, 0xff };
			xui_layout_row(ctx, 1, (int[]){ -1 }, 100);
			xui_colorpicker(ctx, &c);
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Badge"))
		{
			if(xui_begin_tree(ctx, "Normal Badge"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_badge_ex(ctx, wcstr[i], (i << 8));
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Badge"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_badge_ex(ctx, wcstr[i], (i << 8) | XUI_BADGE_ROUNDED);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Outline Badge"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_badge_ex(ctx, wcstr[i], (i << 8) | XUI_BADGE_OUTLINE);
				}
				xui_end_tree(ctx);
			}

			if(xui_begin_tree(ctx, "Rounded Outline Badge"))
			{
				xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 0);
				for(int i = 0; i < 8; i++)
				{
					xui_badge_ex(ctx, wcstr[i], (i << 8) | XUI_BADGE_ROUNDED | XUI_BADGE_OUTLINE);
				}
				xui_end_tree(ctx);
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Progress"))
		{
			xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
			for(int i = 0; i < 8; i++)
			{
				xui_progress_ex(ctx, (i + 1) * 10, (i << 8) | XUI_PROGRESS_HORIZONTAL);
			}
			xui_layout_row(ctx, 8, (int[]){ 24, 24, 24, 24, 24, 24, 24, -1 }, 160);
			for(int i = 0; i < 8; i++)
			{
				xui_progress_ex(ctx, (i + 1) * 10, (i << 8) | XUI_PROGRESS_VERTICAL);
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Radialbar"))
		{
			xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 100);
			for(int i = 0; i < 8; i++)
			{
				xui_radialbar_ex(ctx, (i + 1) * 10, (i << 8));
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Spinner"))
		{
			xui_layout_row(ctx, 3, (int[]){ 100, 100, -1 }, 60);
			for(int i = 0; i < 8; i++)
			{
				xui_spinner_ex(ctx, (i << 8));
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Glass"))
		{
			static int radius = 10;
			xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
			xui_slider_int(ctx, &radius, 1, 100, 1);
			xui_layout_row(ctx, 1, (int[]){ -1 }, 160);
			xui_begin_panel_ex(ctx, "widget", XUI_OPT_NOSCROLL);
			{
				xui_layout_row(ctx, 8, (int[]){ 24, 24, 24, 24, 24, 24, 24, 24 }, -1);
				for(int i = 0; i < 8; i++)
				{
					xui_progress_ex(ctx, (ctx->frame + i * 10) % 100, (i << 8) | XUI_PROGRESS_VERTICAL);
				}
				xui_layout_set_next(ctx, &xui_get_container(ctx)->body, 0);
				xui_glass(ctx, radius);
			}
			xui_end_panel(ctx);
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Split"))
		{
			xui_layout_row(ctx, 1, (int[]){ -1 }, 0);
			for(int i = 0; i < 8; i++)
			{
				xui_split_ex(ctx, (i << 8) | XUI_SPLIT_HORIZONTAL);
			}
			xui_layout_row(ctx, 8, (int[]){ 24, 24, 24, 24, 24, 24, 24, -1 }, 160);
			for(int i = 0; i < 8; i++)
			{
				xui_split_ex(ctx, (i << 8) | XUI_SPLIT_VERTICAL);
			}
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Label"))
		{
			xui_label_ex(ctx, "Label align left", XUI_OPT_TEXT_LEFT);
			xui_label_ex(ctx, "Label align center", XUI_OPT_TEXT_CENTER);
			xui_label_ex(ctx, "Label align right", XUI_OPT_TEXT_RIGHT);
			xui_label_ex(ctx, "Label align top", XUI_OPT_TEXT_TOP);
			xui_label_ex(ctx, "Label align bottom", XUI_OPT_TEXT_BOTTOM);
			xui_end_tree(ctx);
		}

		if(xui_begin_tree(ctx, "Text"))
		{
			xui_text(ctx, "This is a long text to show dynamic window changes on multiline text");
			xui_end_tree(ctx);
		}

		xui_end_window(ctx);
	}
}

static void overview(struct xui_context_t * ctx)
{
	xui_begin(ctx);
	style_window(ctx);
	overview_window(ctx);
	xui_end(ctx);
}

static void xui_draw(struct window_t *w, void *o)
{
	struct xui_context_t *ctx = (struct xui_context_t *)o;
	struct surface_t *s = w->s;
	struct region_t *r, *clip = &ctx->clip;
	union xui_cmd_t *cmd;
	struct matrix_t m;
	struct icon_t ico;
	int count, size;
	int i;

	if ((count = w->rl->count) > 0)
	{
		for (i = 0; i < count; i++)
		{
			r = &w->rl->region[i];
			region_clone(clip, r);
			cmd = NULL;
			while (xui_cmd_next(ctx, &cmd))
			{
				switch (cmd->base.type)
				{
				case XUI_CMD_TYPE_CLIP:
					if (!region_intersect(clip, r, &cmd->clip.r))
						region_init(clip, 0, 0, 0, 0);
					break;
				case XUI_CMD_TYPE_LINE:
					surface_shape_line(s, clip, &cmd->line.p0, &cmd->line.p1, cmd->line.thickness, &cmd->line.c);
					break;
				case XUI_CMD_TYPE_POLYLINE:
					surface_shape_polyline(s, clip, cmd->polyline.p, cmd->polyline.n, cmd->polyline.thickness, &cmd->polyline.c);
					break;
				case XUI_CMD_TYPE_CURVE:
					surface_shape_curve(s, clip, cmd->curve.p, cmd->curve.n, cmd->curve.thickness, &cmd->curve.c);
					break;
				case XUI_CMD_TYPE_TRIANGLE:
					surface_shape_triangle(s, clip, &cmd->triangle.p0, &cmd->triangle.p1, &cmd->triangle.p2, cmd->triangle.thickness, &cmd->triangle.c);
					break;
				case XUI_CMD_TYPE_RECTANGLE:
					surface_shape_rectangle(s, clip, cmd->rectangle.x, cmd->rectangle.y, cmd->rectangle.w, cmd->rectangle.h, cmd->rectangle.radius, cmd->rectangle.thickness, &cmd->rectangle.c);
					break;
				case XUI_CMD_TYPE_POLYGON:
					surface_shape_polygon(s, clip, cmd->polygon.p, cmd->polygon.n, cmd->polygon.thickness, &cmd->polygon.c);
					break;
				case XUI_CMD_TYPE_CIRCLE:
					surface_shape_circle(s, clip, cmd->circle.x, cmd->circle.y, cmd->circle.radius, cmd->circle.thickness, &cmd->circle.c);
					break;
				case XUI_CMD_TYPE_ELLIPSE:
					surface_shape_ellipse(s, clip, cmd->ellipse.x, cmd->ellipse.y, cmd->ellipse.w, cmd->ellipse.h, cmd->ellipse.thickness, &cmd->ellipse.c);
					break;
				case XUI_CMD_TYPE_ARC:
					surface_shape_arc(s, clip, cmd->arc.x, cmd->arc.y, cmd->arc.radius, cmd->arc.a1, cmd->arc.a2, cmd->arc.thickness, &cmd->arc.c);
					break;
				case XUI_CMD_TYPE_SURFACE:
					surface_blit(s, clip, &cmd->surface.m, cmd->surface.s, RENDER_TYPE_GOOD);
					break;
				case XUI_CMD_TYPE_ICON:
					size = min(cmd->icon.w, cmd->icon.h);
					icon_init(&ico, cmd->icon.code, &cmd->icon.c, ctx->f, cmd->icon.family, size);
					matrix_init_translate(&m, cmd->icon.x + (cmd->icon.w - size) / 2, cmd->icon.y + (cmd->icon.h - size) / 2);
					surface_icon(s, clip, &m, &ico);
					break;
				case XUI_CMD_TYPE_TEXT:
					matrix_init_translate(&m, cmd->text.x, cmd->text.y);
					surface_text(s, clip, &m, &cmd->text.txt);
					break;
				case XUI_CMD_TYPE_GLASS:
					surface_effect_glass(s, clip, cmd->glass.x, cmd->glass.y, cmd->glass.w, cmd->glass.h, cmd->glass.radius);
					break;
				case XUI_CMD_TYPE_GRADIENT:
					surface_effect_gradient(s, clip, cmd->gradient.x, cmd->gradient.y, cmd->gradient.w, cmd->gradient.h, &cmd->gradient.lt, &cmd->gradient.rt, &cmd->gradient.rb, &cmd->gradient.lb);
					break;
				case XUI_CMD_TYPE_CHECKERBOARD:
					surface_effect_checkerboard(s, clip, cmd->checkerboard.x, cmd->checkerboard.y, cmd->checkerboard.w, cmd->checkerboard.h);
					break;
				default:
					break;
				}
			}
		}
	}
}

static void event_loop(struct window_t *w, struct xui_context_t *ctx, void (*func)(struct xui_context_t *))
{
	struct event_t e;
	int64_t delta;
	char utf8[16];
	int l, sz;

	while (ctx->running)
	{
		while(window_pump_event(w, &e))
		{
			switch(e.type)
			{
			case EVENT_TYPE_KEY_DOWN:
				switch(e.e.key_down.key)
				{
				case KEY_POWER:
					ctx->key_down |= XUI_KEY_POWER;
					ctx->key_pressed |= XUI_KEY_POWER;
					break;
				case KEY_UP:
					ctx->key_down |= XUI_KEY_UP;
					ctx->key_pressed |= XUI_KEY_UP;
					break;
				case KEY_DOWN:
					ctx->key_down |= XUI_KEY_DOWN;
					ctx->key_pressed |= XUI_KEY_DOWN;
					break;
				case KEY_LEFT:
					ctx->key_down |= XUI_KEY_LEFT;
					ctx->key_pressed |= XUI_KEY_LEFT;
					break;
				case KEY_RIGHT:
					ctx->key_down |= XUI_KEY_RIGHT;
					ctx->key_pressed |= XUI_KEY_RIGHT;
					break;
				case KEY_VOLUME_UP:
					ctx->key_down |= XUI_KEY_VOLUME_UP;
					ctx->key_pressed |= XUI_KEY_VOLUME_UP;
					break;
				case KEY_VOLUME_DOWN:
					ctx->key_down |= XUI_KEY_VOLUME_DOWN;
					ctx->key_pressed |= XUI_KEY_VOLUME_DOWN;
					break;
				case KEY_VOLUME_MUTE:
					ctx->key_down |= XUI_KEY_VOLUME_MUTE;
					ctx->key_pressed |= XUI_KEY_VOLUME_MUTE;
					break;
				case KEY_TAB:
					ctx->key_down |= XUI_KEY_TAB;
					ctx->key_pressed |= XUI_KEY_TAB;
					break;
				case KEY_HOME:
					ctx->key_down |= XUI_KEY_HOME;
					ctx->key_pressed |= XUI_KEY_HOME;
					break;
				case KEY_BACK:
					ctx->key_down |= XUI_KEY_BACK;
					ctx->key_pressed |= XUI_KEY_BACK;
					break;
				case KEY_MENU:
					ctx->key_down |= XUI_KEY_MENU;
					ctx->key_pressed |= XUI_KEY_MENU;
					break;
				case KEY_ENTER:
					ctx->key_down |= XUI_KEY_ENTER;
					ctx->key_pressed |= XUI_KEY_ENTER;
					break;
				case KEY_L_CTRL:
				case KEY_R_CTRL:
					ctx->key_down |= XUI_KEY_CTRL;
					ctx->key_pressed |= XUI_KEY_CTRL;
					break;
				case KEY_L_ALT:
				case KEY_R_ALT:
					ctx->key_down |= XUI_KEY_ALT;
					ctx->key_pressed |= XUI_KEY_ALT;
					break;
				case KEY_L_SHIFT:
				case KEY_R_SHIFT:
					ctx->key_down |= XUI_KEY_SHIFT;
					ctx->key_pressed |= XUI_KEY_SHIFT;
					break;
				default:
					if(e.e.key_up.key >= KEY_SPACE)
					{
						ucs4_to_utf8(&e.e.key_up.key, 1, utf8, sizeof(utf8));
						l = strlen(ctx->input_text);
						sz = strlen(utf8) + 1;
						if(l + sz <= sizeof(ctx->input_text))
							memcpy(ctx->input_text + l, utf8, sz);
					}
					break;
				}
				break;
			case EVENT_TYPE_KEY_UP:
				switch(e.e.key_up.key)
				{
				case KEY_POWER:
					ctx->key_down &= ~XUI_KEY_POWER;
					break;
				case KEY_UP:
					ctx->key_down &= ~XUI_KEY_UP;
					break;
				case KEY_DOWN:
					ctx->key_down &= ~XUI_KEY_DOWN;
					break;
				case KEY_LEFT:
					ctx->key_down &= ~XUI_KEY_LEFT;
					break;
				case KEY_RIGHT:
					ctx->key_down &= ~XUI_KEY_RIGHT;
					break;
				case KEY_VOLUME_UP:
					ctx->key_down &= ~XUI_KEY_VOLUME_UP;
					break;
				case KEY_VOLUME_DOWN:
					ctx->key_down &= ~XUI_KEY_VOLUME_DOWN;
					break;
				case KEY_VOLUME_MUTE:
					ctx->key_down &= ~XUI_KEY_VOLUME_MUTE;
					break;
				case KEY_TAB:
					ctx->key_down &= ~XUI_KEY_TAB;
					break;
				case KEY_HOME:
					ctx->key_down &= ~XUI_KEY_HOME;
					break;
				case KEY_BACK:
					ctx->key_down &= ~XUI_KEY_BACK;
					break;
				case KEY_MENU:
					ctx->key_down &= ~XUI_KEY_MENU;
					break;
				case KEY_ENTER:
					ctx->key_down &= ~XUI_KEY_ENTER;
					break;
				case KEY_L_CTRL:
				case KEY_R_CTRL:
					ctx->key_down &= ~XUI_KEY_CTRL;
					break;
				case KEY_L_ALT:
				case KEY_R_ALT:
					ctx->key_down &= ~XUI_KEY_ALT;
					break;
				case KEY_L_SHIFT:
				case KEY_R_SHIFT:
					ctx->key_down &= ~XUI_KEY_SHIFT;
					break;
				default:
					break;
				}
				break;
			case EVENT_TYPE_MOUSE_DOWN:
				ctx->mouse.x = e.e.mouse_down.x;
				ctx->mouse.y = e.e.mouse_down.y;
				ctx->mouse.state |= e.e.mouse_down.button;
				ctx->mouse.down |= e.e.mouse_down.button;
				ctx->mouse.tx = e.e.mouse_down.x;
				ctx->mouse.ty = e.e.mouse_down.y;
				ctx->mouse.tdown = e.timestamp;
				break;
			case EVENT_TYPE_MOUSE_MOVE:
				ctx->mouse.x = e.e.mouse_move.x;
				ctx->mouse.y = e.e.mouse_move.y;
				ctx->mouse.tmove = e.timestamp;
				break;
			case EVENT_TYPE_MOUSE_UP:
				ctx->mouse.x = e.e.mouse_up.x;
				ctx->mouse.y = e.e.mouse_up.y;
				ctx->mouse.state &= ~e.e.mouse_up.button;
				ctx->mouse.up |= e.e.mouse_up.button;
				if(ktime_to_ns(ktime_sub(e.timestamp, ctx->mouse.tmove)) < 50000000LL)
				{
					delta = ktime_to_ns(ktime_sub(e.timestamp, ctx->mouse.tdown));
					if(delta > 0)
					{
						ctx->mouse.vx = (e.e.mouse_up.x - ctx->mouse.tx) * 1000000000LL / delta;
						ctx->mouse.vy = (e.e.mouse_up.y - ctx->mouse.ty) * 1000000000LL / delta;
					}
				}
				break;
			case EVENT_TYPE_MOUSE_WHEEL:
				ctx->mouse.zx += e.e.mouse_wheel.dx;
				ctx->mouse.zy += e.e.mouse_wheel.dy;
				break;
			case EVENT_TYPE_TOUCH_BEGIN:
				if(e.e.touch_begin.id == 0)
				{
					ctx->mouse.ox = ctx->mouse.x = e.e.touch_begin.x;
					ctx->mouse.oy = ctx->mouse.y = e.e.touch_begin.y;
					ctx->mouse.state |= MOUSE_BUTTON_LEFT;
					ctx->mouse.down |= MOUSE_BUTTON_LEFT;
					ctx->mouse.tx = e.e.touch_begin.x;
					ctx->mouse.ty = e.e.touch_begin.y;
					ctx->mouse.tdown = e.timestamp;
				}
				break;
			case EVENT_TYPE_TOUCH_MOVE:
				if(e.e.touch_move.id == 0)
				{
					ctx->mouse.x = e.e.touch_move.x;
					ctx->mouse.y = e.e.touch_move.y;
					ctx->mouse.tmove = e.timestamp;
				}
				break;
			case EVENT_TYPE_TOUCH_END:
				if(e.e.touch_end.id == 0)
				{
					ctx->mouse.x = e.e.touch_end.x;
					ctx->mouse.y = e.e.touch_end.y;
					ctx->mouse.state &= ~MOUSE_BUTTON_LEFT;
					ctx->mouse.up |= MOUSE_BUTTON_LEFT;
					if(ktime_to_ns(ktime_sub(e.timestamp, ctx->mouse.tmove)) < 50000000LL)
					{
						delta = ktime_to_ns(ktime_sub(e.timestamp, ctx->mouse.tdown));
						if(delta > 0)
						{
							ctx->mouse.vx = (e.e.touch_end.x - ctx->mouse.tx) * 1000000000LL / delta;
							ctx->mouse.vy = (e.e.touch_end.y - ctx->mouse.ty) * 1000000000LL / delta;
						}
					}
				}
				break;
			case EVENT_TYPE_SYSTEM_EXIT:
				xui_exit(ctx);
				break;
			default:
				break;
			}
		}
		if (func)
			func(ctx);
		window_present(w, ctx, xui_draw);
	}
}

void render_cairo_init(void);

int main()
{
	render_cairo_init();

	struct window_t *w = window_alloc(800, 500);
	struct xui_context_t *ctx = xui_context_alloc(window_get_width(w), window_get_height(w), w->rl);
	if (ctx)
	{
		// xui_load_lang(ctx, zh_CN, sizeof(zh_CN));
		event_loop(w, ctx, overview);
		xui_context_free(ctx);
	}
	return 0;
}